#pragma once
#include <iostream>
#include <string>
#include <string.h>
#include <cstdio>
#include <functional>

#define SPA " "
#define SPALENGTH strlen(SPA)

#define NEWLINE "\r\n"
#define NEWLINELENGTH strlen(NEWLINE)

// 要发送时，先把它边长形成一个完整的数据报  “size_len”\r\n"x op y"\r\n
//  "size_len"\r\n'exitcode result'\r\n

std::string enlength(const std::string &in)
{
    int sizelength = strlen(in.c_str()) - NEWLINELENGTH;
    std::string send = "";

    send += std::to_string(sizelength);
    send += NEWLINE;
    send += in;
    return send;
}

// 我们的目标是删除前面的一坨,得到是一个序列化的结果
std::string delength(const std::string &in)
{
    auto pos = in.find(NEWLINE);
    if (pos == std::string::npos)
        return nullptr;
    std::string ret = in.substr(pos + NEWLINELENGTH);
    return ret;
}

// “size_len”\r\n"x op y"\r\n
//"size_len"\r\n'exitcode result'\r\n

bool retquset(int sock, std::string &buffer, std::string *out)
{
    // 我需要一个静态的成员来读，因为我们可能会读到多条信息
    // 这个buffer可能受到多线程的干扰
    char message[1024];
    while (true)
    {
        ssize_t n = recv(sock, message, sizeof message - 1, 0);
        if (n > 0)
        {
            message[n] = 0;
            buffer += message;

            int pos = buffer.find(NEWLINE);

            if (pos == std::string::npos)
                continue;
            // 现在,我们的retquest找到了\r\n

            std::string Headers = buffer.substr(0,pos);
            
           // std::cout << "header : " << Headers << std::endl;
            //int headlength = strlen(Headers.c_str());

            int sizelength = std::atoi(Headers.c_str());
           // std::cout << "sizelength : " << sizelength << std::endl;
            // 拿到了size的长度
            int total_len = 2 * NEWLINELENGTH + Headers.size() + sizelength;
            if ( buffer.size() < total_len)
                continue;

            // 走到这里，就真真的拿到了长度
            *out = buffer.substr(0, total_len);

           // std::string text = *out;
           // std::cout << "out = " << text <<std::endl;
            buffer.erase(0, total_len);
            break;
        }
        else
        {
            // 说明客户端已经关闭了写入
            return false;
        }
    }
    return true;
}

// 当然我们今天的代码是阻塞式的读取，所以不适合这样去读
// bool retquestall(int sock, std::string buffer, std::vector<std::string>*outarr)
// {
//     std::string out;
//     while (!retquset(sock, buffer, &out))
//         outarr->push_back(out);

//     return outarr->size() != 0;
// }



// 0正常，1除零错误，2取模错误，3错误的操作符


class Request
{
public:
    Request()
    {
    }

    Request(const int x, const char op, const int y) : _x(x), _y(y), _op(op)
    {
    }

    // x op y\r\n
    bool serilize(std::string *out)
    {
        *out = "";
        std::string x_string = std::to_string(_x);
        std::string y_string = std::to_string(_y);

        *out += x_string;
        *out += SPA;
        *out += _op;
        *out += SPA;
        *out += y_string;
        *out += NEWLINE;
        //printf("%s",out->c_str());
    }

    // 对面随便new一个Request然后desserilize进行赋值
    // x op y\r\n
    bool deserilize(std::string &str)
    {
        auto left = str.find(SPA);
        auto right = str.rfind(SPA);

        if (left == std::string::npos || right == std::string::npos)
            return false;
        if (left == right)
            return false;

        std::string x_string = str.substr(0, left);
        std::string y_string = str.substr(right + 1, str.size() - (right + 1) - NEWLINELENGTH);
        std::string op_string = str.substr(left + 1, 1);

        _x = atoi(x_string.c_str());
        _y = atoi(y_string.c_str());
        _op = op_string[0];

        return true;
    }

public:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    Response()
    {
    }

    // exitcode result\r\n
    bool serilize(std::string *out)
    {
        *out = "";
        std::string x_string = std::to_string(_exitcode);
        std::string y_string = std::to_string(_result);

        *out += x_string;
        *out += SPA;
        *out += y_string;
        *out += NEWLINE;
    }
    // exitcode result\r\n
    bool deserlize(std::string &str)
    {

        auto sign = str.find(SPA);

        if (sign == std::string::npos)
            return false;

        // 我们要知道op永远都只会是一个
        _exitcode = atoi(str.substr(0, sign).c_str());
        _result = atoi(str.substr(sign + 1, 1).c_str());
        return true;
    }

public:
    int _exitcode;
    int _result;
};
